﻿#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //地图显示区域
    displayRect = QRect(0,0,100,100);
    scene = new QGraphicsScene(this);
    ui->graphicsView->setScene(scene);
    view = ui->graphicsView;
    view->setSceneRect(displayRect);

    //显示地址
    fileLabel = new QLabel(this);
    ui->statusBar->addWidget(fileLabel);

    timerId = startTimer(100);
}

MainWindow::~MainWindow()
{
    delete ui;
}

//开始游戏
void MainWindow::on_actionStart_triggered()
{
    QFileInfo info(QCoreApplication::applicationFilePath());
    QString path = info.path();
    QString getPath = QFileDialog::getOpenFileName(this,"请选择文件位置",path,"*.json");

    //清空撤销列表
    undoLists.clear();

    if(getPath.isEmpty() == true)
        return;

    int result = 0;
    QJsonArray array;
    QFile file(getPath);
    if(file.open(QIODevice::ReadOnly|QIODevice::Text))
    {
        QJsonDocument doc;
        QByteArray bytes = file.readAll();
        doc = QJsonDocument::fromJson(bytes);
        file.close();

        QJsonObject obj = doc.object();
        result = obj.value("gridNumbers").toInt();
        if(result == 0)
        {
            QMessageBox::warning(this,"提示","该文件格子数不正确");
            return;
        }
        array = obj.value("roles").toArray();
        int mainRCount=0,boxCount=0,boxReqCount=0;
        foreach(auto mobj,array)
        {
            int roleState = mobj.toObject().value("mrole").toInt();
            switch (roleState) {
            case 0:mainRCount++;break;
            case 1:boxReqCount++;break;
            case 2:boxCount++;break;
            }
        }
        if(mainRCount != 1)
        {
            QMessageBox::warning(this,"提示","该文件主角数量不正确");
            return;
        }
        if((boxReqCount != boxCount)||(boxCount == 0))
        {
            QMessageBox::warning(this,"提示","箱子数量不正确");
            return;
        }
    }
    filePath = getPath;
    fileLabel->setText(filePath);
    gridNumbers = result;
    initUi(result);

    foreach(auto mobj,array)
    {
        int roleState = mobj.toObject().value("mrole").toInt();
        int mx = mobj.toObject().value("mx").toInt();
        int my = mobj.toObject().value("my").toInt();
        switch (roleState) {
            case 0:
            {
                mRole->setPos(vectorGround[mx][my]->pos());
                mRole->setPoint(mx,my);
                mRole->show();
                break;
            }
            case 1:
            case 2:
            case 3:
            {
                MyMainRole* role = new MyMainRole(mWidth,roleState);
                scene->addItem(role);
                listRole.append(role);
                role->setPos(vectorGround[mx][my]->pos());
                role->setPoint(mx,my);
                role->show();
//                connect(role,&MyMainRole::sendGarbageDisplay,this,&MainWindow::reciveGarbageDis);
                break;
            }
        }
    }
    isStart = true;
}

void MainWindow::timerEvent(QTimerEvent *event)
{
    if(event->timerId() == timerId)
    {
        if(isStart == true)
        {
            if(saveSize != this->size())
            {
                qreal widWidth = view->width();
                qreal widHeight = view->height();
                qreal widMin = (widWidth>widHeight)?widHeight:widWidth;
                view->scale(1.0/hasScaled,1.0/hasScaled);
                double scale = widMin/100;
                view->scale(scale,scale);
                hasScaled = scale;
                saveSize = this->size();
            }

            if(PressTime > 0)
                PressTime--;
        }
    }
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    if(isStart == false)
        return;
    int moveTimes = 2;
    if(PressTime > 0)
        return;

    int key = event->key();
    qDebug() << "press:" << event->text();
    int towards = 0;
    //获得当前的位置
    QPoint curPoint = mRole->getPoint();
    QPoint willPoint1 = curPoint;
    QPoint willPoint2 = curPoint;
    switch(key)
    {
    case Qt::Key_W:
        {
            towards = 0;
            willPoint1.setY(curPoint.y()-1);
            willPoint2.setY(curPoint.y()-2);
            PressTime = moveTimes;
            break;
        }
        case Qt::Key_S:
        {
            towards = 1;
            willPoint1.setY(curPoint.y()+1);
            willPoint2.setY(curPoint.y()+2);
            PressTime = moveTimes;
            break;
        }
        case Qt::Key_A:
        {
            towards = 2;
            willPoint1.setX(curPoint.x()-1);
            willPoint2.setX(curPoint.x()-2);
            PressTime = moveTimes;
            break;
        }
        case Qt::Key_D:
        {
            towards = 3;
            willPoint1.setX(curPoint.x()+1);
            willPoint2.setX(curPoint.x()+2);
            PressTime = moveTimes;
            break;
        }
    }
    mRole->setTowards(towards);

    int role1 = getRoleByPoint(willPoint1);
    int role2 = getRoleByPoint(willPoint2);
    //假如前面是箱子需求或者空的
    if((role1 == 1)||(role1 == -1))
    {
        moveRole(curPoint,willPoint1);
        oneUndoOperate oper;
        undoSaveOneOp op;
        op.origin = curPoint;
        op.destination = willPoint1;
        oper.append(op);
        undoLists.append(oper);
    }
    //假如前面是箱子
    else if(role1 == 2)
    {
        if(role2 == -1)
        {
            moveRole(willPoint1,willPoint2);
            moveRole(curPoint,willPoint1);

            oneUndoOperate oper;
            undoSaveOneOp op;
            op.origin = willPoint1;
            op.destination = willPoint2;
            oper.append(op);

            op.origin = curPoint;
            op.destination = willPoint1;
            oper.append(op);
            undoLists.append(oper);
        }
        else if(role2 == 1){
            moveRole(willPoint1,willPoint2);
            moveRole(curPoint,willPoint1);

            oneUndoOperate oper;
            undoSaveOneOp op;
            op.origin = willPoint1;
            op.destination = willPoint2;
            oper.append(op);

            op.origin = curPoint;
            op.destination = willPoint1;
            oper.append(op);
            undoLists.append(oper);

            //判断游戏是否胜利
            QList<QPoint> boxs;
            QList<QPoint> reqs;
            foreach(auto* mrole,listRole)
            {
                if(mrole->getState() == 1)
                    reqs.append(mrole->getPoint());
                else if(mrole->getState() == 2)
                    boxs.append(mrole->getPoint());
            }
            if(boxs.count() == reqs.count())
            {
                foreach(QPoint mpoi,boxs)
                {
                    int index = reqs.indexOf(mpoi);
                    if( index >= 0)
                        reqs.takeAt(index);
                }
            }
            if(reqs.count() == 0)
            {
                QMessageBox::information(this,"提示","您已胜利！！！");
            }
        }
    }

}

//void MainWindow::keyReleaseEvent(QKeyEvent *event)
//{
//    int key = event->key();
//    qDebug() << "release:" << event->text();
//    switch(key)
//    {
//    case Qt::Key_W:
//        case Qt::Key_S:
//        case Qt::Key_A:
//        case Qt::Key_D:
//            isPress = false;
//        break;
//    default:break;
//    }
//}

void MainWindow::initUi(int grids)
{
    scene->clear();
    vectorGround.clear();

    int width = displayRect.width();
    int height = displayRect.height();

    int min = (width>height)?height:width;

    scene->setSceneRect(displayRect);

    qreal widWidth = view->width();
    qreal widHeight = view->height();
    qreal widMin = (widWidth>widHeight)?widHeight:widWidth;
    view->scale(1.0/hasScaled,1.0/hasScaled);
    double scale = widMin/100;
    view->scale(scale,scale);
    hasScaled = scale;

    QRect rect(5,5,min-10,min-10);
    double onewidth = (min-20.0)/grids;
    mWidth = onewidth;

    QGraphicsRectItem* item = new QGraphicsRectItem(rect);

    scene->addItem(item);

    //绘制棋盘格
    for (int col=0;col<grids;col++) {
        QVector<MyGrid*> onegrid;
        for (int row=0;row<grids;row++) {
            MyGrid* pix = new MyGrid(onewidth,&listRole,0);
            pix->setPos(10+onewidth*col,10+onewidth*row);
            pix->setPoint(col,row);
            scene->addItem(pix);
            onegrid.append(pix);
//            connect(pix,&MyGrid::sendPoi,this,&MainWindow::recivePoi);
        }
        vectorGround.append(onegrid);
    }
    //将主角绘制出来
    mRole = new MyMainRole(onewidth,0);
    mRole->setPos(1.123,1.123);
    scene->addItem(mRole);
//  connect(mRole,&MyMainRole::sendGarbageDisplay,this,&MainWindow::reciveGarbageDis);

    listRole.clear();
    listRole.append(mRole);

    saveSize = this->size();
}

//检查指定位置的角色是什么内容
//0123角色 需求箱子 箱子 墙
//-1表示空
//-2表示出边界
int MainWindow::getRoleByPoint(QPoint poi)
{
    int ret = -1;
    if((poi.x()<0)||(poi.x()>=gridNumbers)||(poi.y()<0)||(poi.y()>=gridNumbers))
    {
        return -2;
    }
    foreach(auto* role,listRole)
    {
        if(role->getPoint() == poi)
        {
            if(role->getState() == 1)
            {
                ret = 1;
            }
            else {
                return role->getState();
            }
        }
    }
    return ret;
}

//角色移动到格子
void MainWindow::moveRole(QPoint RolePoi,QPoint toPoi)
{
    foreach(auto* role,listRole)
    {
        if(role->getPoint() == RolePoi)
        {
            if((role->getState() == 0)||(role->getState() == 2))
            {
                role->setX((vectorGround[toPoi.x()][toPoi.y()])->x());
                role->setY((vectorGround[toPoi.x()][toPoi.y()])->y());
                role->setPoint(toPoi.x(),toPoi.y());
                break;
            }
        }
    }
}

//撤销动作
void MainWindow::on_actionUndo_triggered()
{
    qDebug() << "撤销" ;
    //如果撤销列表空就返回
    if(undoLists.count() == 0)
        return;

    oneUndoOperate last = undoLists.at(undoLists.count()-1);
    undoLists.pop_back();

    int counts = last.count();
    for (int index=counts-1;index>=0;index--) {
        undoSaveOneOp op = last.at(index);
        moveRole(op.destination,op.origin);
    }
}
